#include "server.hpp"
#include <memory>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <sys/wait.h>
#include <cstring>

//请求处理函数
void CommandMessage(int sockfd,std::string ip , uint16_t port, std::string message)
{
    //1创建管道
    int fds[2];

    if(pipe(fds) != 0)
    {
        std::cerr << "input pipe failed in " << ip << "-" << port << std::endl;
        return;
    }
    int pid = fork();
    if(pid > 0)
    {
        //父进程关闭写
        close(fds[1]);
        char buff[1024 * 4] = {0};
        waitpid(pid,nullptr,0);
        int n = read(fds[0],buff,sizeof buff - 1);
        std::cout << buff << std::endl;
        //把返回的结果发给客户端
        struct sockaddr_in client; 
        client.sin_addr.s_addr = inet_addr(ip.c_str());
        client.sin_port = htons(port);
        client.sin_family = AF_INET;
        sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&client,sizeof client);

    }else if(pid == 0)
    {
        //子进程关闭读
        close(fds[0]); 
        char buff[1024] = {0};
        
        //解析命令行
        int idx = 0 ;
        std::vector<std::string> cmds;
        //把命令行参数分解到cmds中
        while(true)
        {
            int pos = message.find(" ",idx); 
            if(pos == std::string::npos) 
            {
            // std::cout<< message << pos << std::endl;
                cmds.push_back(message.substr(idx,pos - idx)); 
                break;
            }
            if(idx != pos) 
            {
                cmds.push_back(message.substr(idx,pos - idx)); 
            }
            idx = pos + 1;   
        }
        const char* ev[128] = {0};  //存储所有的参数

        //把cmds中所有的参数放进ev中
        for(int i = 0; i < cmds.size() ;i++){ ev[i] = cmds[i].c_str(); }
        dup2(fds[1],1);// 相当于close(1) -> close(fds[1]) -> open(fds[1])
        execvp(ev[0],(char* const *)ev); //程序替换
        exit(1);
    } 
}


int main(int argc , char* argv[])
{
    if(argc != 2) //命令行参数不为2就退出
    {
        std::cout << "Usage : " << argv[0] << "   bindport" << std::endl;  //打印使用手册
        exit(1);
    }
    uint16_t port = atoi(argv[1]); //命令行传的端口转换成16位整形
    std::unique_ptr<UdpServer> s(new UdpServer(port,CommandMessage)); //创建UDP服务器，并传入一个回调函数处理请求
    s->init(); //初始化服务器，创建 + 绑定
    s->start(); //运行服务器
}